<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>this_call和apply例子</title>

</head>

<body>
    <h1>this_call和apply例子</h1>
    <div id="div1">我是一个div</div>
    <script>
        // JavaScript 的 this 总是指向一个对象，而具体指向哪个对象是在运行时基于函数的执行环境动态绑定的，而非函数被声明时的环境
        //this的指向
        //1.作为对象的方法调用
        // 当函数作为对象的方法被调用时， this 指向该对象：
        var obj = {
            a: 1,
            getA: function () {
                console.log(this === obj);
                console.log(this.a);
            }
        };
        obj.getA();

        //2.作为普通函数调用
        // 当函数不作为对象的属性被调用时，也就是我们常说的普通函数方式，此时的 this 总是指向全局对象,在浏览器的JavaScript里，这个全局对象是window对象
        window.name = 'globalName';
        var getName = function () {
            return this.name;
        };

        console.log(getName());

        window.id = 'window';
        // document.getElementById('div1').onclick = function () {
        //     console.log(this.id); //this --> div
        //     var callback = function () {
        //         console.log(this.id); //this --> window
        //     }
        //     callback();
        // }

        document.getElementById('div1').onclick = function () {
            console.log(this.id); //this --> div
            var that = this; // that --> div
            var callback = function () {
                console.log(that.id); //that --> div
            }
            callback();
        }

        //在use strict模式下this是未定义的，不会指向全局对象window
        function func() {
            "use strict"
            console.log(this);
        }
        func();

        //3.构造器调用
        var MyClass = function () {
            this.name = 'sven';
        };
        var obj = new MyClass();
        console.log(obj.name); // 输出： sven

        // 但用 new 调用构造器时，还要注意一个问题，如果构造器显式地返回了一个 object 类型的对象，那么此次运算结果最终会返回这个对象，而不是我们之前期待的 this：
        var MyClass = function () {
            this.name = 'sven';
            return { // 显式地返回一个对象
                name: 'anne'
            }
        };
        var obj = new MyClass();
        console.log(obj.name); // 输出： anne
        // 如果构造器不显式地返回任何数据，或者是返回一个非对象类型的数据，就不会造成上述问题：

        //4.Function.propotype.call或Function.prototype.apply调用
        // 跟普通的函数调用相比，用 Function.prototype.call 或 Function.prototype.apply 可以动态地改变传入函数的 this：
        var obj1 = {
            name: 'sven',
            getName: function () {
                return this.name;
            }
        };
        var obj2 = {
            name: 'anne'
        };
        console.log(obj1.getName()); // 输出: sven
        console.log(obj1.getName.call(obj2)); // 输出： anne
    </script>
</body>

</html>